package com.bidevalution.business.impl;

import com.bidevalution.business.context.UserRoleType;
import com.bidevalution.business.service.BeSectionDecryptService;
import com.bidevalution.business.service.BeSectionInfoService;
import com.bidevalution.dao.entity.*;
import com.bidevalution.dao.jdbc.ExecuteStoredProcedure;
import com.bidevalution.dao.mapper.*;
import com.bidevalution.service.ZbFileService;
import com.bidevalution.support.context.Constants;
import com.bidevalution.support.context.SectionStateEnum;
import com.bidevalution.support.util.FileUtil;
import com.ggzy.tongyi.dubbo.api.EnterPriseInfoDubboService;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.qtp.auth.api.ParamsService;
import com.qtp.common.core.TSUser;
import com.qtp.core.config.PropertiesTookit;
import com.qtp.core.model.Paging;
import com.qtp.core.model.Response;
import com.qtp.core.util.DateUtil;
import com.qtp.core.util.FileUtils;
import com.qtp.core.util.GsonUtil;
import com.qtp.core.util.OConvertUtils;
import com.qtp.user.models.SysParams;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 获取标段信息接口实现类
 *
 * @author shenhui
 */

/**
 * ZTKP-4044
 * 【任务】删除及备份两个功能加开关控制，是否对mango进行操作，解决连接的问题
 * 查慧英
 * 2020/3/24
 * 2020-04-02 胡一奇 bug 导光盘模式无法查看招标文件里的其他附件
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class BeSectionInfoServiceImpl implements BeSectionInfoService {
    private static final Logger log = LoggerFactory.getLogger(BeSectionInfoServiceImpl.class);
    @Autowired(required = false)
    private BeSectionInfoMapper beSectionInfoMapper;
    @Autowired(required = false)
    private EnterPriseInfoDubboService enterPriseInfoDubboService;
    @Autowired(required = false)
    private BeSectionParamsMapper beSectionParamsMapper;
    @Autowired(required = false)
    private BeSectionDecryptService beSectionDecryptService;
    @Autowired(required = false)
    private ParamsService paramsService;
    @Autowired(required = false)
    private BeSectionStepJobMapper beSectionStepJobMapper;
    @Autowired(required = false)
    private FileCompareResultMapper fileCompareResultMapper;
    @Autowired(required = false)
    private BeSectionEnterpriseMapper beSectionEnterpriseMapper;
    @Autowired(required = false)
    private BeBackupConfigMapper beBackupConfigMapper;
    @Autowired(required = false)
    private MongoMapper mongoMapper;
    @Autowired(required = false)
    BeSysParamsMapper beSysParamsMapper;
    /*Begin 2020-04-02 胡一奇 bug 导光盘模式无法查看招标文件里的其他附件*/
    @Autowired(required = false)
    private ZbFileService zbFileService;
    public static final Integer DOWNLOAD_TENDER_FILE_RETRY = OConvertUtils.getInt(PropertiesTookit.getValue("DOWNLOAD_TENDER_FILE_RETRY"), 3);
    /*End 2020-04-02 胡一奇 bug 导光盘模式无法查看招标文件里的其他附件*/
    @Value("${spring.datasource.username}")
    private String userName;
    @Value("${spring.datasource.driver-class-name}")
    private String driverName;
    @Value("${spring.datasource.url}")
    private String url;
    @Value("${spring.datasource.password}")
    private String password;
    @Value("${download.file.path}")
    private String downloadFileUrl;
    @Value("${backup.file.path}")
    private String backupPath;
    /**
     * 获取今日开标/历史开标数据
     *
     * @param paramsMap
     * @return
     * @throws Exception
     */
    @Override
    public Paging<List<BeSectionInfo>> getBeSectionListPaging(Map<String, Object> paramsMap) throws Exception {
        String sectionName = "%" + OConvertUtils.getString(paramsMap.get("sectionName")) + "%";
        paramsMap.put("sectionName", sectionName);
        Map<String, Object> enterParams = new HashMap<>();
        enterParams.put("ep_guid", paramsMap.get("enterpriseId"));
        // 获取企业组织机构代码
        Response<Map<String, Object>> response = enterPriseInfoDubboService.getEnterInfo(enterParams);
        String orgCode = "";
        if (response != null && response.isSuccess() && response.getResult() != null) {
            orgCode = OConvertUtils.getString(response.getResult().get("ep_org_code"));
        }
        // 获取分页参数
        int limit = OConvertUtils.getInt(paramsMap.get("rp"), 10);
        int page = OConvertUtils.getInt(paramsMap.get("page"), 1);
        Page<BeSectionInfo> beSectionInfoPage = PageHelper.startPage(page, limit);
        Integer type = OConvertUtils.getInt(paramsMap.get("type"));
        boolean isEnterUserType = Boolean.parseBoolean(OConvertUtils.getString(paramsMap.get("isEnterUserType")));
        String enterpriseId = OConvertUtils.getString(paramsMap.get("enterpriseId"));
        List<BeSectionInfo> list = beSectionInfoMapper.getBeSectionList(type, sectionName, isEnterUserType, orgCode,
                enterpriseId);
        return new Paging(beSectionInfoPage.getTotal(), list);

    }

    /**
     * 根据id获取标段信息
     *
     * @param seqId
     * @return
     */
    @Override
    public BeSectionInfo getBeSectionInfoById(String seqId) {
        return beSectionInfoMapper.selectByPrimaryKey(seqId);
    }

    /**
     * 更新标段状态
     *
     * @param sectionId
     * @param sectionStage
     * @return
     */
    @Override
    public Boolean updateSectionStage(String sectionId, String sectionStage) throws Exception {
        if (beSectionInfoMapper.updateSectionStage(sectionId, sectionStage) > 0) {
            if (SectionStateEnum.decrypting.getValue().equals(sectionStage)) {
                Date now = new Date();
                // 新增解密开始时间
                beSectionParamsMapper.insertBeSectionParams(sectionId, "decryptStartTime",
                        DateUtil.dateToString(now, DateUtil.PT2));
                SysParams sysParams = paramsService.querySysParamsByCode("decryptTime");
                if (sysParams != null) {
                    // 新增解密截止时间
                    beSectionParamsMapper.insertBeSectionParams(sectionId, "decryptEndTime",
                            DateUtil.dateToString(DateUtil.getAfterMinute(now, Integer.valueOf(sysParams.getSypaValue())), DateUtil.PT2));
                }
            }
            return true;
        }

        return false;
    }

    @Override
    public List<BeSectionInfo> getLiveBeSectionList() {
        return beSectionInfoMapper.getLiveBeSectionList();
    }

    @Override
    public List<BeSectionInfo> getLiveListByRoom(String roomName) {
        return beSectionInfoMapper.getLiveListByRoom(roomName);
    }

    @Override
    public List<BeSectionInfo> getChatSectionList() {
        return beSectionInfoMapper.getChatSectionList();
    }

    @Override
    public Paging<List<BeSectionInfo>> getAllList(Map<String, Object> paramsMap) throws Exception {
        // 获取分页参数
        int limit = OConvertUtils.getInt(paramsMap.get("rp"), 10);
        int page = OConvertUtils.getInt(paramsMap.get("page"), 1);
        Page<BeSectionInfo> beSectionInfoPage = PageHelper.startPage(page, limit);
        String sectionName = null;
        if (StringUtils.isNotBlank(OConvertUtils.getString(paramsMap.get("sectionName")))) {
            sectionName = "%" + OConvertUtils.getString(paramsMap.get("sectionName")) + "%";
        }
        Map<String, Object> enterParams = new HashMap<>();
        enterParams.put("ep_guid", paramsMap.get("enterpriseId"));
        // 获取企业组织机构代码
        Response<Map<String, Object>> response = enterPriseInfoDubboService.getEnterInfo(enterParams);
        String orgCode = null;
        if (response != null && response.isSuccess() && response.getResult() != null) {
            orgCode = OConvertUtils.getString(response.getResult().get("ep_org_code"));
        }
        List<BeSectionInfo> list = beSectionInfoMapper.getAllList(sectionName, orgCode);
        return new Paging(beSectionInfoPage.getTotal(), list);
    }

    @Override
    public UserRoleType getUserRoleType(String sectionId, TSUser loginUser, List<String> roleList) throws Exception {
        for (String role : roleList) {
            if (UserRoleType.JGRY.getValue().equals(role)) {
                // 监管人员
                return UserRoleType.JGRY;
            } else if (UserRoleType.JYXRY.getValue().equals(role)) {
                // 中心人员
                return UserRoleType.JYXRY;
            } else if (UserRoleType.ZBDL.getValue().equals(role) || UserRoleType.ZBR.getValue().equals(role)
                    || UserRoleType.TBR.getValue().equals(role)) {
                Map<String, Object> params = new HashMap<>();
                params.put("ep_guid", loginUser.getOrgId());
                // 获取请求中的参数
                Response<Map<String, Object>> response = enterPriseInfoDubboService.getEnterInfo(params);
                // 获取当前用户组织机构代码
                String orgCode = "";
                if (response.getResult() != null) {
                    orgCode = String.valueOf(response.getResult().get("ep_org_code"));
                }
                // 判断是否是招标代理
                BeSectionInfo beSectionInfo = getBeSectionInfoById(sectionId);
                if (beSectionInfo != null && orgCode.equals(beSectionInfo.getAgentOrgCode())) {
                    return UserRoleType.ZBDL;
                }
                // 判断是否是投标单位
                BeSectionDecrypt beSectionDecrypt = beSectionDecryptService.getBeSectionDecryptInfoByCode(sectionId, orgCode);
                if (beSectionDecrypt != null) {
                    return UserRoleType.TBR;
                }

            }
        }
        return null;
    }

    /**
     * 获取今日开标项目数据
     *
     * @return
     */
    @Override
    public List<BeSectionInfo> getTodaySectionList() {
        return beSectionInfoMapper.getTodaySectionList();
    }

    @Override
    public List<BeSectionInfo> getAgentSectionList(Map<String, Object> paramsMap) throws Exception {
        //获取查询条件
        String sectiName = OConvertUtils.getString(paramsMap.get("sectiName"));
        String sectiCode = OConvertUtils.getString(paramsMap.get("sectiCode"));
        String orgCode = OConvertUtils.getString(paramsMap.get("orgCode"));
        String startTime = OConvertUtils.getString(paramsMap.get("startTime"));
        String endTime = OConvertUtils.getString(paramsMap.get("endTime"));
        List<BeSectionInfo> sectionList = beSectionInfoMapper.getAgentSectionList(sectiName, sectiCode, orgCode, startTime, endTime);
        return sectionList;
    }

    /**
     * 获取专家权限下今日评审项目列表
     * @param loginName 专家登录名
     * @return
     * @throws Exception
     */
    @Override
    public List<BeSectionInfo> getExpertSectionList(String loginName) throws Exception {
        return beSectionInfoMapper.getExpertSectionList(loginName);
    }

	@Override
	public List<BeSectionInfo> getListByBidOpenTime(Date startDate, Date endDate) {
		// TODO Auto-generated method stub
		return beSectionInfoMapper.getListByBidOpenTime(startDate, endDate);
	}

	@Override
	public List<BeSectionInfo> getAllSectionList(String orgCode,String areaId, String sectionName, String sectionCode) {

		return beSectionInfoMapper.getAllSectionList(orgCode,areaId, sectionName,sectionCode);
	}

    @Override
    public Response<String> updateReviewStart(String sectionId) throws Exception {
        //判断项目是不是二阶段项目，判断项目所有投标单位的投标报价是否都为空，都为空则是二阶段
        Integer isTwoStage = Constants.ZERO;
        List<BeSectionEnterprise> enterList = beSectionEnterpriseMapper.queryEnterpriseByIdAndPrice(sectionId);
        if (enterList.size() == Constants.ZERO) {
            isTwoStage = Constants.ONE;
        }
        BeSectionInfo beSectionInfo = new BeSectionInfo();
        beSectionInfo.setSeqId(sectionId);
        beSectionInfo.setReviewState(2);
        beSectionInfo.setIsTwoStage(isTwoStage);
        beSectionInfo.setReviewStartTime(DateUtil.now());
        beSectionInfo.setUpdateTime(DateUtil.now());
        //更新标段评审状态为可以评审
        if (beSectionInfoMapper.updateByPrimaryKeySelective(beSectionInfo) < 1) {
            throw new Exception("更新标段评审状态失败！");
        }
        //二阶段项目不在这里提前计算
        BeSectionStepJob beSectionStepJob = new BeSectionStepJob();
        if (Constants.ZERO.equals(isTwoStage)) {
            //更新需要提前执行任务的状态为可以执行
            beSectionStepJob.setSectionId(sectionId);
            beSectionStepJob.setIsAdvanceExecute(Constants.STATE_Y);
            //2表示可以执行（用于提前执行的任务）
            beSectionStepJob.setJobState(Constants.TWO);
            beSectionStepJob.setUpdateTime(DateUtil.now());
            //更新标段环节任务状态为可以执行
            beSectionStepJobMapper.updateStepJobBySectionId(beSectionStepJob);
        }else{
            //删除商务标之前的提前计算任务，本地二阶段商务标之前不需要系统进行提前计算
            beSectionStepJob.setSectionId(sectionId);
            beSectionStepJob.setIsAdvanceExecute(Constants.STATE_Y);
            beSectionStepJob.setIsBusinessBefore(Constants.ONE);
            beSectionStepJobMapper.deleteStepJobByCondition(beSectionStepJob);
            //二阶段的项目需要把部分任务做变更，例如计算基准价或者最佳报价
            /*BeSectionStepJob _beSectionStepJob = new BeSectionStepJob();
            _beSectionStepJob.setSectionId(sectionId);
            _beSectionStepJob.setJobName("TWO_STAGE_UPDATE");
            _beSectionStepJob.setIsAdvanceExecute(Constants.STATE_Y);
            _beSectionStepJob.setJobState(Constants.ONE);
            _beSectionStepJob.setStage(null);
            _beSectionStepJob.setUpdateTime(DateUtil.now());
            beSectionStepJobMapper.updateAdvanceJob(_beSectionStepJob);*/
        }
        return Response.ok();
    }

    @Override
    public boolean updateSectionInfoById(String sectionId, Integer status) throws Exception {
        BeSectionInfo beSectionInfo = new BeSectionInfo();
        beSectionInfo.setSeqId(sectionId);
        beSectionInfo.setReviewState(status);
        beSectionInfo.setReviewEndTime(DateUtil.now());
        beSectionInfo.setUpdateTime(DateUtil.now());
        //更新标段评审状态为评审结束
        if (beSectionInfoMapper.updateByPrimaryKeySelective(beSectionInfo) < 1) {
            return false;
        }
        return true;
    }

	@Override
	public BeSectionInfo selectByCode(String code) {
		// TODO Auto-generated method stub
		return beSectionInfoMapper.getSectionInfoByCode(code);
	}
    @Override
    public Response deleteBySectionId(String sectionCode, String sectionName)  {
        BeSectionInfo sectionInfo = beSectionInfoMapper.getSectionInfoByCodeAndName(sectionCode, sectionName);
        if (sectionInfo == null) {
            return Response.fail("标段信息为空");
        }
        String sectionId = sectionInfo.getSeqId();
        String projectId = sectionInfo.getTdProjectid();

        //删除标段下所有文件
        //begin
        //ZTKP-4044
        // 【任务】删除及备份两个功能加开关控制，是否对mango进行操作，解决连接的问题
        // 查慧英
        // 2020/3/24
        List<BeSysParams> list = beSysParamsMapper.selectForList("deleteMango");
        if (list != null && !list.isEmpty()) {
            BeSysParams sysParams = list.get(0);
            if (OConvertUtils.getInt(sysParams.getSypaValue()) == 1) {
                mongoMapper.dropCollections(projectId);
            }
        }
        //end
        String sql="{call delStep(?)}";
        Object [] params = {sectionId};
        ExecuteStoredProcedure procedure = new ExecuteStoredProcedure(url, driverName, userName, password);
        procedure.executeUpdate(sql, params);
        sql="{call delPro(?)}";
        Object [] params2 = {projectId};
        return procedure.executeUpdate(sql, params2);
    }
    @Override
    public Response deleteEnterprise(String sectionId, String enterpriseId) {
        BeSectionInfo sectionInfo = beSectionInfoMapper.getSectionInfoById(sectionId);
        String projectId = sectionInfo.getTdProjectid();
        List<String> fileIds = fileCompareResultMapper.getEnterpriseFiles(projectId, enterpriseId);
        //删除企业的所有文件
        //begin
        //ZTKP-4044
        // 【任务】删除及备份两个功能加开关控制，是否对mango进行操作，解决连接的问题
        // 查慧英
        // 2020/3/24
        List<BeSysParams> list = beSysParamsMapper.selectForList("deleteMango");
        if (list != null && !list.isEmpty()) {
            BeSysParams sysParams = list.get(0);
            if (OConvertUtils.getInt(sysParams.getSypaValue()) == 1) {
                mongoMapper.deleteFiles(projectId, fileIds);
            }
        }
        //end

        String sql="{call delStepByEnterprise(?,?)}";
        Object [] params = {sectionId,enterpriseId};
        ExecuteStoredProcedure procedure = new ExecuteStoredProcedure(url, driverName, userName, password);
        procedure.executeUpdate(sql, params);
        Object [] params2 = {projectId, enterpriseId};
        sql="{call delProByEnterprise(?,?)}";
        return procedure.executeUpdate(sql, params2);
    }

    @Transactional(rollbackFor=Exception.class)
    @Override
    public Response backupBySectionId(String ids) throws Exception {
        List<BeSectionInfo> sectionList = beSectionInfoMapper.getListByIds(ids);
        if (sectionList != null && !sectionList.isEmpty()) {
            String sectionId;
            String projectId;
            StringBuilder sqlStr;
            for (BeSectionInfo sectionInfo : sectionList) {
                //根据项目id备份数据库
                projectId = sectionInfo.getTdProjectid();
                sectionId = sectionInfo.getSeqId();
                List<Map<String, Object>> list = beBackupConfigMapper.getList();
                if (list != null && !list.isEmpty()) {
                    sqlStr = new StringBuilder();
                    for (Map<String, Object> item : list) {
                        item.put("sectionId", sectionId);
                        item.put("projectId", projectId);
                        item.put("sectionCode", sectionInfo.getSectionCode());
                        List<Map<String, Object>> dataList = beBackupConfigMapper.getDataList(item);
                        sqlStr = assembleInsertSql(dataList, item,  sqlStr);
                    }
                    writeToSqlFile(sqlStr, sectionId);
                }
                //根据项目id备份mango
                //begin
                //ZTKP-4044
                // 【任务】删除及备份两个功能加开关控制，是否对mango进行操作，解决连接的问题
                // 查慧英
                // 2020/3/24
                List<BeSysParams> params = beSysParamsMapper.selectForList("backupMango");
                if (params != null && !params.isEmpty()) {
                    BeSysParams sysParams = params.get(0);
                    if (OConvertUtils.getInt(sysParams.getSypaValue()) == 1) {
                        backupMango(projectId);
                    }
                }

            }
        }
        return Response.ok();

    }

    @Override
    public long getValidUnitNum(String sectionId) {
        log.info("LOG[]getValidUnitNum[]{},params={}", "获取有效单位数",sectionId);
        return beSectionInfoMapper.getValidUnitNum(sectionId);
    }
    /*Begin 2020-04-02 胡一奇 bug 导光盘模式无法查看招标文件里的其他附件*/
    @Async
    @Override
    public Response downloadZbPdfs(BeSectionInfo beSectionInfo) throws Exception {
        String pdfMd5 = beSectionInfo.getTenderFileMd5();
        Response<String> rsp = Response.ok();
        if(StringUtils.isBlank(pdfMd5)) {
            Map<String, Object> tender = new Hashtable<>(8);
            tender.put("TenderNo", beSectionInfo.getSectionCode());
            rsp = zbFileService.downloadTenderFiles(tender);
            if(!rsp.isSuccess()) {
                int num = 0;
                while(num<DOWNLOAD_TENDER_FILE_RETRY && !rsp.isSuccess()) {
                    rsp = zbFileService.downloadTenderFiles(tender);
                }
            }
            if(rsp.isSuccess()) {
                log.info("线下模式下载招标文件pdf成功");
            } else {
                log.error("线下模式下载招标文件pdf失败");
            }
        }
        return rsp;
    }
    /*End 2020-04-02 胡一奇 bug 导光盘模式无法查看招标文件里的其他附件*/
    private void backupMango(String projectId) throws Exception {
        List<Map> list = mongoMapper.getMangoFilesInfo(projectId);
        if (list != null && !list.isEmpty()) {
            String filePath;
            for (Map map: list) {
                String id = OConvertUtils.getString(map.get("_id"));
                log.info("文件id："+id);
                String realFileName = OConvertUtils.getString(map.get("REAL_FILE_NAME"));
                downloadFileUrl = String.format("%s/UploadedFile/", downloadFileUrl);
                filePath = String.format("%s%s/%s/%s", backupPath, projectId, id, realFileName);
                FileUtil.downloadFile(downloadFileUrl, id, filePath);

            }
        }

    }

    private StringBuilder assembleInsertSql(List<Map<String, Object>> dataList, Map<String, Object> item, StringBuilder sqlStr) {
        if (dataList != null && !dataList.isEmpty()) {
            sqlStr.append("INSERT INTO ").append(item.get("table_name")).append(" (");
            Map<String, Object> keyMap = dataList.get(0);
            int keyNum = 0;
            for (Object key : keyMap.keySet()) {
                if (keyNum > 0) {
                    sqlStr.append(", ");
                }
                sqlStr.append(key);
                keyNum++;
            }
            sqlStr.append(") VALUES ");
            Map<String, Object> data;
            int lenth = 0;
            int valueNum;
            for (int j = 0; j < dataList.size(); j++) {
                sqlStr.append("\n");
                if (j > 0) {
                    sqlStr.append(",");
                }
                data = dataList.get(j);
                lenth = keyMap.size();
                valueNum = 0;
                for (Object key : keyMap.keySet()) {
                    sqlStr = assembleInsertSql(sqlStr, data.get(key), valueNum, lenth);
                    valueNum++;
                }
            }
            sqlStr.append(";").append("\n");
        }
        return sqlStr;
    }

    private StringBuilder assembleInsertSql(StringBuilder sqlStr, Object result, int i, int length) {
        if (i == 0) {
            sqlStr.append("(");
        } else {
            sqlStr.append(",");
        }
        if(result instanceof String) {
            sqlStr.append("'").append(((String) result).replace("'", "\\'")).append("'");
        } else if(result instanceof Date) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            sqlStr.append("'").append(format.format(result)).append("'");
        } else {
            sqlStr.append(result);
        }
        if (i == length-1) {
            sqlStr.append(")");
        }
        return sqlStr;
    }
    public void writeToSqlFile(StringBuilder buffer, String sectionId) throws IOException {
        String backName = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String filePath=String.format("%s%s/%s.sql", backupPath, backName, sectionId);
        String directory = filePath.substring(0,filePath.lastIndexOf("/"));
        FileUtils.createDirectory(directory);
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath))){
            bw.write(buffer.toString());
        } catch (Exception e) {
            log.error("LOG[]writeToSqlFile_489[]{},error={}","异常日志", GsonUtil.toJsonWithGson(e));
        }
    }
}
